package tsif.tcluster.service.proxy;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

import tsif.tcluster.TClusterContext;
import tsif.tcluster.TClusterContext.IServiceAction;
import tsif.tcluster.service.ITClusterService;

/**
 * 服务管理器<br>
 * 
 */
public class TClusterServices {
	protected TClusterContext context; // 环境

	protected AtomicInteger serviceCounter; // 本机服务自增Id
	protected ConcurrentMap<Long, TClusterServiceProxy> services; // 服务节点表

	public TClusterServices(TClusterContext context) {
		this.context = context;

		serviceCounter = new AtomicInteger();
		services = new ConcurrentHashMap<>();
	}

	/** 创建和初始化服务节点 **/
	public TClusterServiceProxy addAndInitServiceProxy(TClusterServiceProxy serviceProxy, long serviceId, String uniqueName, Class<?> classValue, Object... args) throws Exception {
		boolean success = false;
		try {
			// add to services(先添加, 保证init的callback处理)
			TClusterServiceProxy old = services.putIfAbsent(serviceId, serviceProxy);
			if (old != null) {
				throw new Exception("服务存在重复Id! serviceId=" + serviceProxy.getServiceId() + " classValue=" + classValue);
			}

			// init service node
			if (!serviceProxy.init(context, serviceId, uniqueName, classValue, args)) {
				// remove
				services.remove(serviceId, serviceProxy);
				// error
				throw new Exception("初始化服务失败! serviceId=" + serviceProxy.getServiceId() + " classValue=" + classValue);
			}
			success = true;
		} finally {
			if (!success) {
				// 失败销毁节点
				if (serviceProxy != null) {
					serviceProxy.destroy();
					serviceProxy = null;
				}
			}
		}
		return serviceProxy;
	}

	/** 获取所有服务 **/
	public Collection<TClusterServiceProxy> getAll() {
		return services.values();
	}

	/** 获取所有服务 **/
	public Set<Long> getServiceIds() {
		return services.keySet();
	}

	/** 删除服务 **/
	public boolean remove(long serviceId) {
		TClusterServiceProxy serviceProxy = services.remove(serviceId);
		if (serviceProxy == null) {
			return false;
		}

		// destroy
		try {
			if (serviceProxy != null) {
				serviceProxy.destroy(); // call destroy
				serviceProxy = null;
			}
		} catch (Exception e) {
			System.err.println("destroy service error!" + serviceProxy.getServiceId());
			e.printStackTrace();
		}
		return true;
	}

	/** 获取服务 **/
	public TClusterServiceProxy get(long serviceId) {
		return services.get(serviceId);
	}

	/** 更新遍历器 **/
	private static IServiceAction updateAction = new IServiceAction() {
		@Override
		public void action(TClusterServiceProxy serviceProxy, ITClusterService service) throws Exception {
			serviceProxy.update(); // 执行更新
		}
	};

	/** 更新服务 **/
	public void update() {
		forech(updateAction);
	}

	/** 遍历执行服务 **/
	public void forech(IServiceAction action) {
		List<TClusterServiceProxy> list = new ArrayList<>(services.values());
		for (TClusterServiceProxy proxy : list) {
			try {
				ITClusterService service = (ITClusterService) proxy.getService();
				if (service == null) {
					continue; // 尚未初始化完成
				}
				// 执行
				action.action(proxy, (ITClusterService) proxy.getService());
			} catch (Exception e) {
				System.err.println("service action error! " + proxy.getServiceId() + " " + proxy.getService() + " error=" + e.toString());
				e.printStackTrace();
			}
		}
	}

	/** 获取一个服务Id(集群唯一/本机唯一) **/
	public long newServiceId() {
		int contextId = context.getContextId();
		for (int i = 0; i < 100; i++) {
			long serviceId = getServiceId(contextId, serviceCounter.incrementAndGet());
			if (!services.containsKey(serviceId)) {
				return serviceId;
			}
		}
		throw new RuntimeException("can't get new service id!");
	}

	/** 新建服务Id **/
	public long getServiceId(int index) {
		int contextId = context.getContextId();
		return getServiceId(contextId, index);
	}

	/** 新建服务Id **/
	public static long getServiceId(int contextId, int index) {
		return contextId * 100000L + index;
	}

	/** 通过服务器Id获取设备Id **/
	public static int getContextId(long serviceId) {
		return (int) (serviceId / 100000L);
	}

	/** 本地服务Id **/
	public static long getLocalServiceId(int contextId) {
		return getServiceId(contextId, 0);
	}

}
